package com.chucang.shucang.usr.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.chucang.shucang.common.base.constant.CommonConstant;
import com.chucang.shucang.common.base.constant.SecurityConstant;
import com.chucang.shucang.common.base.exception.FastException;
import com.chucang.shucang.common.base.page.PageData;
import com.chucang.shucang.common.base.utils.OpsUtil;
import com.chucang.shucang.common.base.utils.R;
import com.chucang.shucang.common.mq.constant.RabbitConstant;
import com.chucang.shucang.common.mq.to.BlindBoxOrderBaseTO;
import com.chucang.shucang.common.mq.to.NFTPublishTO;
import com.chucang.shucang.common.security.entity.ShuCangUser;
import com.chucang.shucang.common.security.utils.SecurityUtil;
import com.chucang.shucang.usr.constant.UsrCommonConstant;
import com.chucang.shucang.usr.entity.UserBaseEntity;
import com.chucang.shucang.usr.entity.UserBlindBoxHoldEntity;
import com.chucang.shucang.usr.entity.UserWalletEntity;
import com.chucang.shucang.usr.exception.UsrErrorCode;
import com.chucang.shucang.usr.feign.OmsService;
import com.chucang.shucang.usr.feign.PmsService;
import com.chucang.shucang.usr.feign.vo.*;
import com.chucang.shucang.usr.service.UserBaseService;
import com.chucang.shucang.usr.service.UserBlindBoxHoldService;
import com.chucang.shucang.usr.service.UserWalletService;
import com.chucang.shucang.usr.vo.*;
import com.chucang.shucang.usr.vo.query.UserBlindBoxHoldQuery;
import com.github.yitter.idgen.YitIdHelper;
import io.swagger.annotations.Api;
import lombok.RequiredArgsConstructor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 用户盲盒信息
 *
 * @author flitsneak flitsneak@gmail.com
 * @since 1.0.0 2022-09-12
 */
@RestController
@RequestMapping("/userblindboxhold")
@RequiredArgsConstructor
@Api(tags = "用户盲盒信息")
public class UserBlindBoxHoldController {

    private final UserBlindBoxHoldService userBlindBoxHoldService;
    private final UserBaseService userBaseService;
    private final UserWalletService userWalletService;

    private final PmsService pmsService;
    private final OmsService omsService;
    private final RabbitTemplate rabbitTemplate;

    /**
     * 获取用户拥有盲盒信息
     *
     * @param userBlindBoxHoldQuery ubq
     * @return r
     */
    @PostMapping("/userBlindBoxPage")
    public R<PageData<UserBlindBoxHoldResVO>> userBlindBoxPage(@Valid @RequestBody UserBlindBoxHoldQuery userBlindBoxHoldQuery) {
        PageData<UserBlindBoxHoldResVO> pageData = userBlindBoxHoldService.userBlindBoxPage(userBlindBoxHoldQuery);
        return R.ok(pageData);
    }

    /**
     * 盲盒编号列表
     *
     * @param userBlindBoxSerialNumVO ubs
     * @return r
     */
    @PostMapping("/blindBoxSerialNumList")
    public R<List<UserBlindBoxSerialNumResVO>> blindBoxSerialNumList(@Valid @RequestBody UserBlindBoxSerialNumVO userBlindBoxSerialNumVO) {
        List<UserBlindBoxSerialNumResVO> list = userBlindBoxHoldService.blindBoxSerialNumList(userBlindBoxSerialNumVO);
        return R.ok(list);
    }

    /**
     * 寄售盲盒
     *
     * @param userBlindBoxOnConsignVO
     * @return
     */
    @PostMapping("/blindBoxesOnConsign")
    public R<String> blindBoxesOnConsign(@Valid @RequestBody UserBlindBoxOnConsignVO userBlindBoxOnConsignVO) {
        //是否开通钱包
        LambdaQueryWrapper<UserWalletEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserWalletEntity::getUserId, userBlindBoxOnConsignVO.getUserId());
        UserWalletEntity one = userWalletService.getOne(queryWrapper);
        if (Objects.isNull(one)) {
            return R.failed(UsrErrorCode.NO_WALLET_FOUND.getCode(), UsrErrorCode.NO_WALLET_FOUND.getMsg());
        }
        if (userBlindBoxHoldService.blindBoxesOnConsign(userBlindBoxOnConsignVO)) {
            return R.ok();
        }
        return R.failed();
    }

    /**
     * 我的盲盒详情
     *
     * @param id 盲盒id
     * @return
     */
    @GetMapping("/myBlindBoxDetail/{id}")
    public R<MyBlindBoxDetailResVO> myBlindBoxDetail(@PathVariable Long id) {
        LambdaQueryWrapper<UserBlindBoxHoldEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserBlindBoxHoldEntity::getUserId, SecurityUtil.getUser().getId())
                .eq(UserBlindBoxHoldEntity::getBbId, id)
                .select(UserBlindBoxHoldEntity::getSerialNum);
        List<UserBlindBoxHoldEntity> list = userBlindBoxHoldService.list(queryWrapper);
        if (CollUtil.isEmpty(list)) {
            return R.failed();
        }
        //盲盒基础信息
        R<BlindBoxBaseEntity> blindBoxBaseInfo = pmsService.getBlindBoxBaseInfo(id, SecurityConstant.FROM_IN);
        BlindBoxBaseEntity blindBoxBaseEntity = OpsUtil.of(blindBoxBaseInfo)
                .assertDataNotNull(e -> new FastException("查询盲盒信息异常！"))
                .getData()
                .get();
        MyBlindBoxDetailResVO myBlindBoxDetailResVO = new MyBlindBoxDetailResVO();
        List<Integer> serialNumList = new ArrayList<>(16);
        list.forEach(b -> serialNumList.add(b.getSerialNum()));
        myBlindBoxDetailResVO
                .setHoldNum(list.size())
                .setDetailPicture(blindBoxBaseEntity.getDetailPicture())
                .setBbDisplay(blindBoxBaseEntity.getBbDisplay())
                .setBbDisplayType(blindBoxBaseEntity.getBbDisplayType())
                .setBbName(blindBoxBaseEntity.getBbName())
                .setSerialNumList(serialNumList)
                .setBbPrice(blindBoxBaseEntity.getBbPrice());

        return R.ok(myBlindBoxDetailResVO);
    }

    /**
     * 开启盲盒
     *
     * @param id        盲盒id
     * @param serialNum 盲盒编号
     * @return r
     */
    @Transactional(rollbackFor = Exception.class)
    @GetMapping("/openBlindBox/{id}/{serialNum}")
    public R<OpenBlindBoxResVO> openBlindBox(@PathVariable Long id, @PathVariable Integer serialNum) {
        //自己盲盒校验排查
        LambdaQueryWrapper<UserBlindBoxHoldEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper
                .eq(UserBlindBoxHoldEntity::getUserId, SecurityUtil.getUser().getId())
                .eq(UserBlindBoxHoldEntity::getBbId, id)
                .eq(UserBlindBoxHoldEntity::getSerialNum, serialNum)
                .eq(UserBlindBoxHoldEntity::getStatus, UsrCommonConstant.BLIND_BOX_HOLD)
                .select();
        UserBlindBoxHoldEntity one = userBlindBoxHoldService.getOne(lambdaQueryWrapper);
        if (Objects.isNull(one)) {
            return R.failed();
        }
        //持有盲盒状态同步
        LambdaUpdateWrapper<UserBlindBoxHoldEntity> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(UserBlindBoxHoldEntity::getId, one.getId())
                .set(UserBlindBoxHoldEntity::getStatus, UsrCommonConstant.BLIND_BOX_OPEN);
        userBlindBoxHoldService.update(lambdaUpdateWrapper);
        //pms表获取盲盒真实信息
        R<BlindBoxBasicOpenResVO> resVO = pmsService.openBlindBox(id, serialNum, SecurityConstant.FROM_IN);
        BlindBoxBasicOpenResVO openResVO = OpsUtil.of(resVO)
                .assertDataNotNull(e -> new FastException("开启盲盒异常！"))
                .getData()
                .get();
        OpenBlindBoxResVO openBlindBoxResVO = new OpenBlindBoxResVO();
        BeanUtil.copyProperties(openResVO, openBlindBoxResVO);
        NFTPublishTO nftPublishTO = new NFTPublishTO();
        nftPublishTO
                .setName(openResVO.getSerialNum().toString())
                .setRecipient(SecurityUtil.getUser().getOffshoreAccount())
                .setClass_id(CommonConstant.CLASS_ID_PREFIX + openResVO.getId())
                .setUserId(SecurityUtil.getUser().getId())
                .setOperation_id(CommonConstant.NFT_PUBLISH_PREFIX + YitIdHelper.nextId())
                .setSourceType(UsrCommonConstant.FROM_BLIND_BOX);
        rabbitTemplate.convertAndSend(RabbitConstant.NFT_EXCHANGE, RabbitConstant.NFT_PUBLISH_NFT_KEY, nftPublishTO);
        return R.ok(openBlindBoxResVO);
    }

    /**
     * 商城藏品id
     *
     * @param id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @GetMapping("/purchaseBlindBox/{id}")
    public R<PurchaseResVO> purchaseBlindBox(@PathVariable Long id) {
        ShuCangUser user = SecurityUtil.getUser();
        if (Objects.isNull(user)) {
            return R.failed();
        }
        Long userId = user.getId();
        //是否开通钱包
        LambdaQueryWrapper<UserWalletEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserWalletEntity::getUserId, userId);
        UserWalletEntity one = userWalletService.getOne(queryWrapper);
        if (Objects.isNull(one)) {
            return R.failed(UsrErrorCode.NO_WALLET_FOUND.getCode(), UsrErrorCode.NO_WALLET_FOUND.getMsg());
        }
        //校验用户是否实名认证
        if (user.getIsRealAuth() != UsrCommonConstant.REAL_NAME_AUTH) {
            UserBaseEntity userBaseEntity = userBaseService.getById(userId);
            if (userBaseEntity.getIsRealAuth() != UsrCommonConstant.REAL_NAME_AUTH) {
                return R.failed(UsrErrorCode.NO_REAL_NAME_AUTH.getCode(), UsrErrorCode.NO_REAL_NAME_AUTH.getMsg());
            }
        }
        //锁定库存
        R<BlindBoxMallEntity> mallEntity = pmsService.lockBlindBoxStock(id, userId, SecurityConstant.FROM_IN);
        BlindBoxMallEntity blindBoxMallEntity = OpsUtil.of(mallEntity)
                .assertCode(CommonConstant.SUCCESS, e -> new FastException("锁定库存失败！"))
                .getData()
                .get();
        //创建订单，发送到订单服务
        long orderId = YitIdHelper.nextId();
        BlindBoxOrderBaseTO blindBoxOrderBaseTO = new BlindBoxOrderBaseTO();
        blindBoxOrderBaseTO.setId(orderId);
        blindBoxOrderBaseTO.setBbId(blindBoxMallEntity.getBbId());
        blindBoxOrderBaseTO.setOrderAmount(blindBoxMallEntity.getSellingPrice());
        long sub = userId % 1000000;
        String orderSn = String.valueOf(orderId) + sub;
        blindBoxOrderBaseTO.setOrderSn(orderSn);
        blindBoxOrderBaseTO.setUserId(userId);
        blindBoxOrderBaseTO.setOrderType(UsrCommonConstant.NORMAL_PURCHASE);
        blindBoxOrderBaseTO.setOrderNum(1);

        //订单服务同步写入
        R<String> collectionOrder = omsService.createBlindBoxOrder(blindBoxOrderBaseTO, SecurityConstant.FROM_IN);
        OpsUtil.of(collectionOrder)
                .assertCode(CommonConstant.SUCCESS, e -> new FastException("写入订单异常！"));
        //放人死信队列
        rabbitTemplate.convertAndSend(RabbitConstant.ORDER_EXCHANGE, RabbitConstant.ORDER_CREATE_ORDER_KEY, blindBoxOrderBaseTO);

        R<BlindBoxBaseEntity> blindBoxBaseInfo = pmsService.getBlindBoxBaseInfo(blindBoxMallEntity.getBbId(), SecurityConstant.FROM_IN);
        BlindBoxBaseEntity blindBoxBaseEntity = OpsUtil.of(blindBoxBaseInfo)
                .assertCode(CommonConstant.SUCCESS, e -> new FastException("获取订单信息异常！"))
                .getData()
                .get();
        PurchaseResVO purchaseResVO = new PurchaseResVO();
        purchaseResVO.setOrderSn(orderSn);
        purchaseResVO.setProductType(UsrCommonConstant.COLLECTION);
        purchaseResVO.setPurchaseNum(1);
        purchaseResVO.setCreateTime(new Date());
        purchaseResVO.setCoverPicture(blindBoxBaseEntity.getCoverPicture());
        purchaseResVO.setTotalAmount(blindBoxMallEntity.getSellingPrice());
        purchaseResVO.setSerialNum(blindBoxMallEntity.getSerialNum());
        purchaseResVO.setProductSerialNum(String.format(UsrCommonConstant.SERIAL_NUM, blindBoxMallEntity.getSerialNum(), blindBoxBaseEntity.getTotalNum()));
        return R.ok(purchaseResVO);
    }
}